package com.vcc.boss.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.hutool.core.util.IdUtil;
import com.mybatisflex.core.paginate.Page;
import com.vcc.channel.base.model.request.CardCancelDto;
import com.vcc.channel.base.service.ChannelBaseService;
import com.vcc.core.annotations.RepeatSubmit;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.constant.CardStatusEnum;
import com.vcc.core.exception.ProgramException;
import com.vcc.data.entity.*;
import com.vcc.service.boss.request.risk.*;
import com.vcc.service.boss.response.risk.RiskTransactionLogVoBoss;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.*;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Log4j2
@RestController
@RequestMapping("riskTransactionLog")
public class RiskTransactionLogController {


    @Resource
    private RiskTransactionLogService riskTransactionLogService;
    @Resource
    private UserService userService;
    @Resource
    private CardTypeService cardTypeService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private CardOrderService cardOrderService;
    @Autowired
    private UserCardService userCardService;

    @RestPack
    @GetMapping("paging")
    @SaCheckLogin
    @SaCheckPermission("risk:transaction:list:view")
    public Page<RiskTransactionLogVoBoss> paging(
            Integer pageNumber,
            Integer pageSize,
            Long userId,
            String transactionId,
            String channelTransactionId,
            String channelName,
            String cardNumber,
            Long cardId,
            Integer status
    ) {
        return riskTransactionLogService.paging(
                pageNumber,
                pageSize,
                userId,
                transactionId,
                channelTransactionId,
                channelName,
                cardNumber,
                cardId,
                null,
                status
        );
    }


    @RestPack
    @PostMapping("dispose")
    @SaCheckLogin
    @SaCheckSafe("DISPOSE_RISK_TRANSACTION_LOG")
    @SaCheckPermission("risk:transaction:dispose")
    @RepeatSubmit
    public Boolean disposeRiskTransactionLog(@RequestBody @Validated DisposeTransactionLog disposeRiskTransactionLogDto) {
        RiskTransactionLog riskTransactionLog = riskTransactionLogService.getByIdOpt(disposeRiskTransactionLogDto.getId()).orElseThrow(() -> new ProgramException("风控交易日志不存在"));
        if (riskTransactionLog.getStatus() == 0) {
            throw new ProgramException("该风控交易日志已处理");
        }
        List<RiskTransactionLog> list = null;
        if (disposeRiskTransactionLogDto.getHasSkipRiskCheck()) {
            //检查是否有其他待处理的风控交易日志
            List<RiskTransactionLog> riskTransactionLogs = riskTransactionLogService.listByUserCardIdAndDisposeStatus(
                    riskTransactionLog.getUserCardId(), 1
            );
            if (riskTransactionLogs.isEmpty()) {
                log.info("用户卡ID:{}无待处理风控交易日志", riskTransactionLog.getUserCardId());
            }
            //排除当前处理的风控交易日志
            list = riskTransactionLogs.stream().filter(it -> !it.getId().equals(riskTransactionLog.getId())).toList();
            if (!list.isEmpty()) {
                log.info("用户卡ID:{}有待处理风控交易日志,非当前日志均跳过处理", riskTransactionLog.getUserCardId());
            }
        }
        UserCard userCard = userCardService.getByIdOpt(riskTransactionLog.getUserCardId()).orElseThrow(() -> new ProgramException("用户卡不存在"));
        ChannelBaseService baseService = applicationContext.getBean(riskTransactionLog.getChannelName(), ChannelBaseService.class);
        switch (disposeRiskTransactionLogDto.getFunctionName()) {
            case "ignore-risk":
                // 忽略风控
                riskTransactionLogService.completeTransactionLog(
                        disposeRiskTransactionLogDto.getId(),
                        0,
                        "忽略风控交易",
                        "ignore-risk",
                        BossUserUtil.getId()
                );
                break;
            case "block":
                // 冻结卡
                blockCard(
                        riskTransactionLog,
                        userCard,
                        baseService
                );
                riskTransactionLogService.completeTransactionLog(
                        disposeRiskTransactionLogDto.getId(),
                        0,
                        "冻结卡成功",
                        "block",
                        BossUserUtil.getId()
                );
                break;
            case "close":
                // 关闭卡
                closeCard(
                        riskTransactionLog,
                        userCard,
                        baseService
                );
                riskTransactionLogService.completeTransactionLog(
                        disposeRiskTransactionLogDto.getId(),
                        0,
                        "关闭卡成功",
                        "close",
                        BossUserUtil.getId()
                );
                break;
            case "block-user-block-card":
                blockUser(
                        riskTransactionLog.getUserId()
                );
                blockCard(
                        riskTransactionLog,
                        userCard,
                        baseService
                );
                riskTransactionLogService.completeTransactionLog(
                        disposeRiskTransactionLogDto.getId(),
                        0,
                        "冻结用户及卡成功",
                        "block-user-block-card",
                        BossUserUtil.getId()
                );
                break;
            case "block-user-close-card":
                blockUser(
                        riskTransactionLog.getUserId()
                );
                closeCard(
                        riskTransactionLog,
                        userCard,
                        baseService
                );
                riskTransactionLogService.completeTransactionLog(
                        disposeRiskTransactionLogDto.getId(),
                        0,
                        "冻结用户及关闭卡成功",
                        "block-user-close-card",
                        BossUserUtil.getId()
                );
                break;
            default:
                throw new ProgramException("不支持的处理方法");
        }
        if (list != null && !list.isEmpty()) {
            //批量跳过处理
            riskTransactionLogService.completeTransactionLog(
                    list.stream().map(RiskTransactionLog::getId).toList(),
                    0,
                    "系统风控批量跳过处理",
                    "ignore-risk",
                    BossUserUtil.getId()
            );
        }
        return true;
    }

    @RestPack
    @PostMapping("batchDispose")
    @SaCheckLogin
    @SaCheckSafe("BATCH_DISPOSE_RISK_TRANSACTION_LOG")
    @SaCheckPermission("risk:transaction:batch:dispose")
    @RepeatSubmit
    public Boolean batchDisposeRiskTransactionLog(@RequestBody @Validated BatchDisposeTransactionLog disposeRiskTransactionLogDto) {
        for (Long id : disposeRiskTransactionLogDto.getIds()) {
            RiskTransactionLog log = riskTransactionLogService.getByIdOpt(id).orElseThrow(() -> new ProgramException("风控交易日志不存在"));
            if (log.getStatus() == 0) {
                throw new ProgramException("该风控交易日志已处理");
            }
            UserCard userCard = userCardService.getByIdOpt(log.getUserCardId()).orElseThrow(() -> new ProgramException("用户卡不存在"));
            ChannelBaseService baseService = applicationContext.getBean(log.getChannelName(), ChannelBaseService.class);
            switch (disposeRiskTransactionLogDto.getFunctionName()) {
                case "ignore-risk":
                    // 忽略风控
                    riskTransactionLogService.completeTransactionLog(
                            id,
                            0,
                            "忽略风控交易",
                            "ignore-risk",
                            BossUserUtil.getId()
                    );
                    break;
                case "block":
                    // 冻结卡
                    blockCard(
                            log,
                            userCard,
                            baseService
                    );
                    riskTransactionLogService.completeTransactionLog(
                            id,
                            0,
                            "冻结卡成功",
                            "block",
                            BossUserUtil.getId()
                    );
                    break;
                case "close":
                    // 关闭卡
                    closeCard(
                            log,
                            userCard,
                            baseService
                    );
                    riskTransactionLogService.completeTransactionLog(
                            id,
                            0,
                            "关闭卡成功",
                            "close",
                            BossUserUtil.getId()
                    );
                    break;
                case "block-user-block-card":
                    blockUser(
                            log.getUserId()
                    );
                    blockCard(
                            log,
                            userCard,
                            baseService
                    );
                    riskTransactionLogService.completeTransactionLog(
                            id,
                            0,
                            "冻结用户及卡成功",
                            "block-user-block-card",
                            BossUserUtil.getId()
                    );
                    break;
                case "block-user-close-card":
                    blockUser(
                            log.getUserId()
                    );
                    closeCard(
                            log,
                            userCard,
                            baseService
                    );
                    riskTransactionLogService.completeTransactionLog(
                            id,
                            0,
                            "冻结用户及关闭卡成功",
                            "block-user-close-card",
                            BossUserUtil.getId()
                    );
                    break;
                default:
                    throw new ProgramException("不支持的处理方法");
            }
        }

        return true;
    }

    private void blockUser(Long userId) {
        User user = userService.getByIdOpt(userId).orElseThrow(() -> new ProgramException("用户不存在"));
        if (user.getStatus() != null && user.getStatus() == 0) {
            userService.updateStatusAndAdminRemarkById(
                    userId,
                    2,
                    "系统风控冻结用户"
            );
        }
    }

    private void blockCard(RiskTransactionLog riskTransactionLog, UserCard userCard, ChannelBaseService baseService) {
        String requestId = IdUtil.getSnowflakeNextIdStr();
        String cardStatus = baseService.queryCardStatus(userCard.getChannelCardId());
        if (StringUtils.equalsAny(cardStatus, CardStatusEnum.CLOSE.getCode())) {
            userCardService.updateCardStatusByChannelCardId(
                    "CLOSED",
                    userCard.getChannelCardId()
            );
            throw new ProgramException("卡片已关闭，无法冻结");
        }
        if (StringUtils.equalsAny(cardStatus, CardStatusEnum.BLOCKED.getCode())) {
            userCardService.updateCardStatusByChannelCardId(
                    CardStatusEnum.CONTROL.getCode(),
                    userCard.getChannelCardId()
            );
            return;
        }
        cardOrderService.blockCard(
                requestId,
                riskTransactionLog.getCardTypeId(),
                riskTransactionLog.getUserId(),
                BossUserUtil.getId(),
                riskTransactionLog.getCardNumber(),
                riskTransactionLog.getUserCardId(),
                userCard.getChannelCardId(),
                "系统风控冻结卡",
                "SYSTEM"
        );
        baseService.blockCard(userCard.getChannelCardId(), requestId);
        userCardService.updateCardStatusByChannelCardId(
                CardStatusEnum.CONTROL.getCode(),
                userCard.getChannelCardId()
        );
    }

    private void closeCard(RiskTransactionLog riskTransactionLog, UserCard userCard, ChannelBaseService baseService) {
        String requestId = IdUtil.getSnowflakeNextIdStr();
        String cardStatus = baseService.queryCardStatus(userCard.getChannelCardId());
        if (StringUtils.equalsAny(cardStatus, CardStatusEnum.CLOSE.getCode())) {
            userCardService.updateCardStatusByChannelCardId(
                    "CLOSED",
                    userCard.getChannelCardId()
            );
            return;
        }
        cardOrderService.closeCard(
                requestId,
                riskTransactionLog.getCardTypeId(),
                riskTransactionLog.getUserId(),
                BossUserUtil.getId(),
                riskTransactionLog.getCardNumber(),
                riskTransactionLog.getUserCardId(),
                userCard.getChannelCardId(),
                "系统风控关闭卡",
                "SYSTEM"
        );
        baseService.cancelCard(
                CardCancelDto.builder()
                        .channelCardId(userCard.getChannelCardId())
                        .requestId(requestId)
                        .build()
        );
    }

}
